package processor

import (
	"errors"
	"fmt"
	"gitee.com/Luna-CY/hui-hui/internal/logger"
	"gitee.com/Luna-CY/hui-hui/internal/util/goroutine"
	"os"
	"os/exec"
	"path/filepath"
)

// StartApplication 启动应用
func (cls *Processor) StartApplication(name string, command string, args []string, environments []string, working string, restart bool, callback func(state State, err error)) error {
	cls.mutex.Lock()
	defer cls.mutex.Unlock()

	if cls.quiting {
		return errors.New("进程管理器已退出，无法启动应用")
	}

	var application, ok = cls.application[name]
	if !ok {
		application = &Application{name: name, command: command, args: args, environments: environments, working: working, restart: restart, callback: callback}
		cls.application[name] = application
	}

	// 预创建日志路径
	if err := os.MkdirAll(logs, 0755); nil != err {
		return err
	}

	output, err := os.OpenFile(filepath.Join(logs, fmt.Sprintf("%s.log", name)), os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
	if nil != err {
		return err
	}

	application.output = output

	if err := cls.start(application); nil != err {
		return err
	}

	return nil
}

func (cls *Processor) start(application *Application) error {
	application.c = exec.Command(application.command, application.args...)
	application.c.Dir = application.working
	application.c.Env = application.environments
	application.c.Stdout = application.output
	application.c.Stderr = application.output

	application.quiting = false
	application.state = StateStarting
	application.callback(StateStarting, nil)

	// 启动
	if err := application.c.Start(); nil != err {
		application.state = StateStartFailed
		application.callback(StateStartFailed, err)

		return err
	}

	application.pid = int32(application.c.Process.Pid)
	application.state = StateStarted
	application.callback(StateStarted, nil)

	goroutine.Go(func() {
		var err = application.c.Wait()
		if cls.quiting || application.quiting || StateRestarting == application.state {
			return
		}

		application.state = StateRunError
		application.callback(StateRunError, err)
		logger.GetLogger().Sugar().Errorf("进程管理器: 应用异常退出: %s %s", application.name, err)
	})

	return nil
}
